<?php
/**
 * Mortal BBS auth鉴权
 *
 * @author QQ1977441805
 * @copyright Copyright (c) 2024
 */

namespace mortalauth;

use think\Db;
use think\facade\Session;
use think\facade\Config;

class Mortalauth{ 

	protected $auth_config = [
        'user_table'=>'member',//管理员表名  不带前缀
        'auth_table'=>'role',//权限角色表  不带前缀
        'auth_id'=>'purview',//权限绑定字段
        'auth_menu'=>'menu',//权限节点配置表  不带前缀
        'login_state'=>'admin_login_info',//记录登录状态的Session Key
        'auth_type'=>1,//认证方式，1为实时校验；2为登录后校验。
        'auth_super'=>'*ALL*',//超级权限标识
        'offsite_off'=>false,//是否禁止多设备同时登录 false允许  true不允许
    ];

    public function __construct(){
        if (Config::pull('mortalauth')) {
            $this->auth_config = array_merge($this->auth_config, Config::pull('mortalauth'));
        }

	}
    /**
     * 检查用户
     * 默认采用password_hash密码加密验证方式
     * @param  array  $info     需要验证的用户信息  账号：account  密码：password
     * @return array           通过验证返回用户信息;失败返回错误信息
     */
    public function checkuser($info=[]){
        if(!$info||!isset($info['account'])||!isset($info['password'])){
            return ['code'=>-1,'msg'=>'错误的信息'];
        }
        $user = Db::name($this->auth_config['user_table'])->where(['account'=>filter_var($info['account'],FILTER_SANITIZE_STRING),'is_admin'=>2])->find();
        if(!$user){
            return ['code'=>-1,'msg'=>'用户不存在'];
        }
        if(!password_verify($info['password'],$user['password'])){
            return ['code'=>-1,'msg'=>'密码错误!'];
        }
        if($user['status'] !== 1){
            return ['code'=>-1,'msg'=>'账户状态异常!'];
        }
        return ['code'=>200,'msg'=>'登录成功','data'=>$user];
    }
    /**
     * 检查用户权限
     * @param  integer  $uid      认证用户ID
     * @param  string  $route     需要验证的路由节点
     * @return array|boolean           通过验证返回true;失败返回错误信息
     */
    public function check_auth($uid,$route){
        if(!is_numeric($uid)){
            return ['code'=>-1,'msg'=>'uid error'];
        }
        if (is_string($route)) {
            $route = strtolower($route);
            $route = [$route];
        }
        if(!$route){//未传递需要验证的节点，那就不验证
            return true;
        }
        $rule = $this->get_rule();
        if(!$rule){//未配置权限节点，视为无需验证权限也可所有人无权限，目前暂时无需验证
            return true;
            //return ['code'=>-1,'msg'=>'无权限'];
        }
        
        $check_rule = [];
        
        foreach($rule as $v){
            if(in_array(strtolower($v['conditions']), $route)){
                $check_rule[] = $v;//当前路由存在验证规则
            }
        }
        
        if($check_rule){//有当前节点验证信息进入验证
            $user = Db::name($this->auth_config['user_table'])->where(['is_admin'=>2,'id'=>$uid])->find();
            if(!$user){
                return ['code'=>-1,'msg'=>'用户不存在'];
            }
            if(!$user[$this->auth_config['auth_id']] || !isset($user[$this->auth_config['auth_id']])){//权限角色关联无、视为无任何权限
                return ['code'=>-1,'msg'=>'无权限'];
            }

            $role = Db::name($this->auth_config['auth_table'])->where(['id'=>$user[$this->auth_config['auth_id']],'status'=>1])->find();
            
            if(!$role){
                return ['code'=>-1,'msg'=>'角色组不存在/或已停用'];
            }
            
            if(empty($role['conditions'])){
                return ['code'=>-1,'msg'=>'角色组无权限'];
            }
            if($role['conditions'] === $this->auth_config['auth_super']){//角色超级权限，无需验证
                return true;
            }
            if($check_rule[0]['status'] === 2){
                return ['code'=>-1,'msg'=>'当前节点禁止访问'];
            }
            $u_rule = $this->get_rule($role['conditions']);//获取当前用户所有权限节点
            
            if(!$u_rule){//用户持有权限非表中权限，劝退
                return ['code'=>-1,'msg'=>'权限校验信息错误'];
            }
            if($this->auth_config['auth_type'] == 1){//实时校验
            
                if($check_rule[0]['type'] == 1){
                    
                    $login = $this->check_login($user);
                    
                    if($login['code'] == -1){
                        return $login;
                    }else{
                        if(in_array(strtolower($check_rule[0]['conditions']), $u_rule)){
                            return true;
                        }else{
                            return ['code'=>-1,'msg'=>'无权限'];
                        }
                    }
                }else{
                    $login = $this->check_login($user);
                    if($login['code'] == -1){
                        return $login;
                    }else{
                        return true;
                    }
                }
                
            }else if($this->auth_config['auth_type'] == 2){//登录后校验
                $login = $this->check_login($user);
                if($login['code'] == -1){
                    return $login;
                }
                if($check_rule[0]['type'] == 1){
                    if(in_array(strtolower($check_rule[0]['conditions']), $u_rule)){
                        return true;
                    }else{
                        return ['code'=>-1,'msg'=>'无权限'];
                    }
                }else{
                    return true;
                }
                
            }
        }else{
            return true;
        }
        
    }
    
    public function get_rule($u_auth_id=array()){
        $rule = [];
        if($u_auth_id){
            if (is_string($u_auth_id)) {
                $u_auth_id = strtolower($u_auth_id);
                if (strpos($u_auth_id, ',') !== false) {
                    $u_auth_id = explode(',', $u_auth_id);
                } else {
                    $u_auth_id = [$u_auth_id];
                }
            }
            $rule = Db::name($this->auth_config['auth_menu'])->where(['id'=>$u_auth_id])->select();
            if($rule){
                foreach($rule as $k=>$v){
                    if(empty($v['conditions']) || empty($v['type'])){//清除无效规则
                        unset($rule[$k]);
                    }else{
                        $rule[$k] = strtolower($v['conditions']);
                    }
                }
            }
        }else{
            $rule = Db::name($this->auth_config['auth_menu'])->select();
            if($rule){
                foreach($rule as $k=>$v){
                    if(empty($v['conditions']) || empty($v['type'])){//清除无效规则
                        unset($rule[$k]);
                    }
                }
                
            }
        }
        return $rule;
    }
    public function get_user_menu($u_auth_id=array()){
        $menu = [];
        if($u_auth_id){
            if (is_string($u_auth_id)) {
                $u_auth_id = strtolower($u_auth_id);
                if (strpos($u_auth_id, ',') !== false) {
                    $u_auth_id = explode(',', $u_auth_id);
                } else {
                    $u_auth_id = [$u_auth_id];
                }
            }
            $menu = Db::name($this->auth_config['auth_menu'])->where(['status'=>1,'is_menu'=>1,'id'=>$u_auth_id])->order('order_by asc')->select();
        }else{
            $menu = Db::name($this->auth_config['auth_menu'])->where(['status'=>1,'is_menu'=>1])->order('order_by asc')->select();
        }
        return $menu;
    }
    public function check_login(){
        $is_login = Session::get($this->auth_config['login_state']);
        if(!$is_login){
            Session::delete($this->auth_config['login_state']);
            return ['code'=>-1,'msg'=>'请先登录'];
        }else{
            $user = db($this->auth_config['user_table'])->find($is_login['id']);
            if($user){
                if($is_login['account'] != $user['account']){
                    Session::delete($this->auth_config['login_state']);
                    return ['code'=>-1,'msg'=>'登录信息不符，请重新登录'];
                }
                if($this->auth_config['offsite_off']){
                    if($user['login_token'] != $is_login['login_token']){
                        Session::delete($this->auth_config['login_state']);
                        return ['code'=>-1,'msg'=>'您的账号在其他地方登录，请重新登录'];
                    }
                }
                if($user['status'] != $is_login['status']){
                    Session::delete($this->auth_config['login_state']);
                    return ['code'=>-1,'msg'=>'账户状态异常，请重新登录'];
                }else{
                    return true;
                }
            }else{
                return true;
            }
        }
    }
}